package cn.t.keycloak.demo.mfa.sms.credential;

import cn.t.keycloak.demo.mfa.sms.credential.dto.SmsCredentialData;
import cn.t.keycloak.demo.mfa.sms.credential.dto.SmsSecretData;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.common.util.Time;
import org.keycloak.credential.CredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.util.JsonSerialization;

import java.io.IOException;
import java.util.Optional;

/**
 * 扩展用户凭证表,这里新增一种认证凭证(给用户新增一种手机号登录的凭证(后续从这里拿到用户是否开启了手机验证码登录,然后比对验证码即可))
 * @author 陶敏麒
 * @date 2023/11/15 16:19
 */
@Slf4j
public class SmsCredentialModel extends CredentialModel {
    /**
     * 设置一个类别,这个类别会映射到凭证表中的凭证类型
     */
    public static final String TYPE = "SMS_VALIDATE_PHONE";

    /**
     * Credential表中的SECRET_DATA存储了json格式的(不被暴露)认证密钥数据
     */
    @Getter
    private final SmsSecretData smsSecretData;

    /**
     * Credential表中的CREDENTIAL_DATA存储了json格式的(可被暴露的)证书数据
     */
    @Getter
    private final SmsCredentialData smsCredentialData;

    public SmsCredentialModel(SmsCredentialData smsCredentialData, SmsSecretData smsCredentialSecret) {
        this.smsSecretData = smsCredentialSecret;
        this.smsCredentialData = smsCredentialData;
    }

    /**
     * 查询用户的指定类型凭证
     */
    public static Optional<CredentialModel> queryCredentialModelByUser(UserModel userModel) {
        return userModel.credentialManager().getStoredCredentialsByTypeStream(TYPE).findFirst();
    }

    public static SmsCredentialModel create(String phoneNumber, String secValue) {
        // 这里保存一个认证信息就行,存个手机号,用户校验是否存在即可
        SmsCredentialData credentialData = new SmsCredentialData(phoneNumber);
        // secret数据按需添加
        SmsSecretData secretData = new SmsSecretData(secValue);
        SmsCredentialModel model = new SmsCredentialModel(credentialData, secretData);
        model.fillCredentialModelFields();
        return model;
    }

    private void fillCredentialModelFields() {
        try {
            super.setCredentialData(JsonSerialization.writeValueAsString(this.smsCredentialData));
            super.setSecretData(JsonSerialization.writeValueAsString(this.smsSecretData));
            super.setType(TYPE);
            super.setCreatedDate(Time.currentTimeMillis());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 直接从用户凭证构建
     * @param credentialModel 用户凭证
     */
    public static SmsCredentialModel createFromCredentialModel(CredentialModel credentialModel){
        try {
            SmsCredentialData credentialData = JsonSerialization.readValue(credentialModel.getCredentialData(), SmsCredentialData.class);
            SmsSecretData secretData = JsonSerialization.readValue(credentialModel.getSecretData(), SmsSecretData.class);

            SmsCredentialModel smsCredentialModel = new SmsCredentialModel(credentialData, secretData);
            smsCredentialModel.setUserLabel(credentialModel.getUserLabel());
            smsCredentialModel.setCreatedDate(credentialModel.getCreatedDate());
            smsCredentialModel.setType(TYPE);
            smsCredentialModel.setId(credentialModel.getId());
            smsCredentialModel.setSecretData(credentialModel.getSecretData());
            smsCredentialModel.setCredentialData(credentialModel.getCredentialData());
            return smsCredentialModel;
        } catch (IOException e){
            throw new RuntimeException(e);
        }
    }




}
